package src

import (
	"encoding/json"
	"errors"

	ge "gitee.com/haifengat/gin-ex"
	zd "gitee.com/haifengat/zorm-dm/v2"
	"github.com/gin-gonic/gin"
)

var subInstrument = map[string]struct{}{}

func Route(g *gin.RouterGroup) {
	// initEnv() // 与 run24 重复执行时导致错误
	initSSE(g) // 实时更新
	g.GET("/instrument", ge.CreateHandler(getInstrument))
	// 行情
	g.GET("/history", ge.CreateHandler(getHistory))
	// 行情: 最新
	g.GET("/latest", ge.CreateHandler(getLatest))
	// 订阅
	g.POST("/subscript", ge.CreateHandler(postSubscript))
	// 取消
	g.POST("/unsubscript", ge.CreateHandler(postUnsubscript))

	// ================ 交易相关 ==============
	// 接口状态
	g.GET("/login", ge.CreateHandler(getLogin))
	// 权益
	g.GET("/account", ge.CreateHandler(getAccount))
	// 持仓
	g.GET("/position", ge.CreateHandler(getPosition))
	// 委托
	g.GET("/order", ge.CreateHandler(getOrder))
	// 成交
	g.GET("/trade", ge.CreateHandler(getTrade))
	// 下单
	g.POST("/order", ge.CreateHandler(func(ctx *gin.Context) (data any, data2 any, errRtn error) {
		var order OrderInsert
		errRtn = ctx.ShouldBindJSON(&order)
		if errRtn != nil {
			return
		}
		_, rsp := trd.ReqOrderInsertLimit(string(order.InstrumentID), order.Director, order.Offset, order.Price, order.Volume)
		if rsp.ErrorID != 0 {
			errRtn = errors.New(rsp.ErrorMsg.String())
			return
		}
		return
	}))
	g.POST("/cancel", ge.CreateHandler(func(ctx *gin.Context) (data any, data2 any, errRtn error) {
		mp := ge.GetPostParams(ctx)
		if len(mp) > 0 {
			if id, ok := mp[0]["order_id"]; ok {
				if trd.ReqOrderAction(id.(string)) == -9 {
					errRtn = errors.New("未有对应的委托: " + id.(string))
					return
				}
			}
		}
		return
	}))
}

func getInstrument(ctx *gin.Context) (data any, data2 any, errRtn error) {
	p, where, app := ge.GetQryParams(ctx)
	if p != nil {
		data, errRtn = zd.Select[InstrumentField](ctxPG, &zd.PageInfo{PageNo: p.PageNo, PageSize: p.PageSize}, where, app)
	} else {
		data, errRtn = zd.Select[InstrumentField](ctxPG, nil, where, app)
	}
	return
}

func getHistory(ctx *gin.Context) (data any, data2 any, errRtn error) {
	p, where, app := ge.GetQryParams(ctx)
	if p == nil {
		data, errRtn = zd.Select[Bar](ctxPG, nil, where, app)
	} else {
		data2 := &zd.PageInfo{PageNo: p.PageNo, PageSize: p.PageSize}
		data, errRtn = zd.Select[Bar](ctxPG, data2, where, app)
	}
	return
}

func getLatest(ctx *gin.Context) (data any, data2 any, errRtn error) {
	_, where, _ := ge.GetQryParams(ctx)
	if inst, ok := where["instrument_id"]; ok {
		jsons, err := rdb.LRange(ctxRedis, inst.(string), 0, -1).Result()
		if err != nil {
			errRtn = err
		} else {
			bars := make([]Bar, 0)
			for _, v := range jsons {
				var bar = Bar{}
				err = json.Unmarshal([]byte(v), &bar)
				if err != nil {
					errRtn = err
					break
				}
				bars = append(bars, *bar.Fix())
			}
			data = bars
		}
	}
	return
}

func postSubscript(ctx *gin.Context) (data any, data2 any, errRtn error) {
	mps := ge.GetPostParams(ctx)
	if len(mps) > 0 {
		if tmp, ok := mps[0]["instrument_id"]; ok { // instrument:['a','b'] 数组
			for _, v := range tmp.([]any) {
				if _, ok := trd.Instruments[v.(string)]; ok { // 正确的合约
					subInstrument[v.(string)] = struct{}{}
				}
			}
		}
	}
	return
}

func postUnsubscript(ctx *gin.Context) (data any, data2 any, errRtn error) {
	mps := ge.GetPostParams(ctx)
	if len(mps) > 0 {
		if tmp, ok := mps[0]["instrument_id"]; ok { // instrument:['a','b'] 数组
			for _, v := range tmp.([]any) {
				delete(subInstrument, v.(string))
			}
		}
	}
	return
}

// ============== 交易接口 ===================
func getLogin(ctx *gin.Context) (data any, data2 any, errRtn error) {
	data = map[string]any{"is_login": trd != nil && isLogin}
	return
}

func getAccount(ctx *gin.Context) (data any, data2 any, errRtn error) {
	mpAccount := trd.ReqQryTradingAccount()
	var accounts = make([]*AccountField, 0, len(mpAccount))
	for _, v := range mpAccount {
		accounts = append(accounts, new(AccountField).FromCTP(v))
	}
	data = accounts
	return
}

func getPosition(ctx *gin.Context) (data any, data2 any, errRtn error) {
	fs := trd.ReqQryPosition()
	var posis = make([]*PositionField, 0, len(fs))
	for _, v := range fs {
		posis = append(posis, new(PositionField).FromCTP(v))
	}
	data = posis
	return
}

func getOrder(ctx *gin.Context) (data any, data2 any, errRtn error) {
	orders := trd.Orders
	var os = make([]*OrderField, 0, len(orders))
	for _, v := range orders {
		os = append(os, new(OrderField).FromCTP(v))
	}
	data = os
	return
}

func getTrade(ctx *gin.Context) (data any, data2 any, errRtn error) {
	trades := trd.Trades
	var ts = make([]*TradeField, 0, len(trades))
	for _, vv := range trades {
		for _, v := range vv {
			ts = append(ts, new(TradeField).FromCTP(v))
		}
	}
	data = ts
	return
}
